﻿using System;
using System.Collections;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using GameStateManagement;
using System.Threading;

namespace DrWileyO_REDACTED_Adventure.Screens
{
    class GameplayScreen : GameScreen
    {
        InputAction pauseAction;
        ContentManager content;
        SpriteFont gameFont;

        Vector2 playerStartPos;

        Camera cam;

        ArrayList plats;
        ArrayList powerUps;

        MainCharacter mc;

        Texture2D background;
        Texture2D energyBar;

        Texture2D splash;

        float pauseAlpha;

        Texture2D end;
        Texture2D middle;
        Texture2D endv;
        Texture2D middlev;
        Texture2D potionAtlas;
        Texture2D debugHit;

        bool hasWon = false;
        bool dontStartYet = false;

        public GameplayScreen()
        {
            TransitionOnTime = TimeSpan.FromSeconds(1.5);
            TransitionOffTime = TimeSpan.FromSeconds(0.5);

            pauseAction = new InputAction(
                new Buttons[] { Buttons.Start, Buttons.Back },
                new Keys[] { Keys.Escape },
                true);
        }

        public override void Activate(bool instancePreserved)
        {
            if (!instancePreserved)
            {
                if (content == null)
                    content = new ContentManager(ScreenManager.Game.Services, "Content");

                gameFont = content.Load<SpriteFont>("DefaultFont");

                background = content.Load<Texture2D>("background");

                end = content.Load<Texture2D>("pipejoint");
                middle = content.Load<Texture2D>("pipetexture");
                endv = content.Load<Texture2D>("vertpipejoint");
                middlev = content.Load<Texture2D>("vertpipe");
                potionAtlas = content.Load<Texture2D>("PotionAtlas");

                splash = content.Load<Texture2D>("splashscreenwithouttxt");

                energyBar = content.Load<Texture2D>("LASERTEXTURE");

                debugHit = content.Load<Texture2D>("alphaSquare");
                
                plats = Platform.GetLevel(end, middle, endv, middlev, debugHit, gameFont);
                powerUps = PowerUp.GetLevel(potionAtlas, debugHit);

                playerStartPos = new Vector2(-120, 50);
                mc = new MainCharacter(content.Load<Texture2D>("ProfAtlas"), playerStartPos, debugHit, gameFont);
                mc.starting = true;

                cam = new Camera(new Rectangle(0, 0, ScreenManager.GraphicsDevice.Viewport.Width, ScreenManager.GraphicsDevice.Viewport.Height));
                cam.Pos = new Vector2(mc.pos.X + (int)(mc.sprite.Height * mc.sprite.Scale * .5), mc.pos.Y + (int)(mc.sprite.Width * mc.sprite.Scale * .5));

                // A real game would probably have more content than this sample, so
                // it would take longer to load. We simulate that by delaying for a
                // while, giving you a chance to admire the beautiful loading screen.
                Thread.Sleep(1000);

                // once the load has finished, we use ResetElapsedTime to tell the game's
                // timing mechanism that we have just finished a very long frame, and that
                // it should not try to catch up.
                ScreenManager.Game.ResetElapsedTime();  
            }
        }

        public override void Deactivate()
        {
            base.Deactivate();
        }

        public override void Unload()
        {
            content.Unload();
        }

        public override void Update(GameTime gameTime, bool otherScreenHasFocus,
                                                       bool coveredByOtherScreen)
        {
            base.Update(gameTime, otherScreenHasFocus, false);

            for (int i = 0; i < powerUps.Count; ++i)
            {
               ((PowerUp)powerUps[i]).Update(gameTime);
            }

            // Gradually fade in or out depending on whether we are covered by the pause screen.
            if (coveredByOtherScreen)
                pauseAlpha = Math.Min(pauseAlpha + 1f / 32, 1);
            else
                pauseAlpha = Math.Max(pauseAlpha - 1f / 32, 0);


            if (IsActive)
            {
                if (!dontStartYet)
                {
                    if (!hasWon)
                    {
                        for (int i = 0; i < plats.Count; i++)
                        {
                            ((Platform)plats[i]).Update(gameTime);
                        }

                        Vector2 temp = mc.pos;
                        Rectangle temp2 = mc.hitBox;
                        mc.Update(gameTime);

                        bool top = false;
                        bool bottom = false;
                        bool left = false;
                        bool right = false;

                        for (int index = 0; index < powerUps.Count; ++index)
                        {
                            Rectangle tempR = ((PowerUp)powerUps[index]).hitBox;
                            if (tempR.Intersects(mc.hitBox))
                            {
                                SoundManager.Instance.playSound(SoundManager.Sound.pickup);
                                ((PowerUp)powerUps[index]).Remove();
                                mc.AlterEnergy(PowerUp.ENERGY_GAIN);

                                powerUps.Remove((PowerUp)powerUps[index]);
                                if (powerUps.Count == 0)
                                {
                                    Win();
                                    SoundManager.Instance.playSound(SoundManager.Sound.taunt);
                                    return;
                                }
                            }
                        }

                        for (int i = 0; i < plats.Count; i++)
                        {
                            if (((Platform)plats[i]).hitBox.Intersects(mc.hitBox))
                            {
                                Vector2 centerPoint = new Vector2(temp2.Center.X, temp2.Center.Y);
                                Vector2 trav = mc.pos - temp;
                                Vector2 nearCorner = findNearestCorner(temp2, ((Platform)plats[i]).hitBox);

                                Rectangle tempR = ((Platform)plats[i]).hitBox;

                                mc.grounded = false;

                                // Top or Bottom
                                if (centerPoint.X >= tempR.Left - .2 * mc.sprite.Scale * mc.sprite.Width && centerPoint.X <= tempR.Right + .2 * mc.sprite.Scale * mc.sprite.Width)
                                {
                                    // Top
                                    if (centerPoint.Y <= tempR.Top)
                                    {
                                        mc.pos.Y = ((Platform)plats[i]).hitBox.Top - mc.sprite.Height * mc.sprite.Scale;
                                        mc.sprite.position.Y = ((Platform)plats[i]).hitBox.Top - mc.sprite.Height * mc.sprite.Scale;
                                        mc.grounded = true;
                                        top = true;
                                        if (((Platform)plats[i]).isFalling)
                                        {
                                            ((Platform)plats[i]).fallStart = true;
                                        }
                                        mc.starting = false;
                                    }
                                    // Bottom
                                    else
                                    {
                                        mc.hitCeiling = true;
                                        bottom = true;
                                    }
                                }
                                // Left or Right
                                else if (centerPoint.Y >= tempR.Top && centerPoint.Y <= tempR.Bottom)
                                {
                                    // Left
                                    if (centerPoint.X <= tempR.Left)
                                    {
                                        mc.pos.X = ((Platform)plats[i]).hitBox.Left - mc.sprite.Width * mc.sprite.Scale;
                                        mc.sprite.position.X = ((Platform)plats[i]).hitBox.Left - mc.sprite.Width * mc.sprite.Scale;
                                        left = true;
                                    }
                                    // Right
                                    else
                                    {
                                        mc.pos.X = ((Platform)plats[i]).hitBox.Right;
                                        mc.sprite.position.X = ((Platform)plats[i]).hitBox.Right + 1;
                                        right = true;
                                    }
                                }
                                // Corners
                                else
                                {
                                    // Top
                                    if (centerPoint.Y <= tempR.Top)
                                    {
                                        /**     mc.pos.Y = ((Platform)plats[i]).hitBox.Top - mc.sprite.Height * mc.sprite.Scale;
                                              mc.sprite.position.Y = ((Platform)plats[i]).hitBox.Top - mc.sprite.Height * mc.sprite.Scale;
                                              mc.grounded = true;
                                              top = true; 

                                              // Left
                                              if (centerPoint.X <= tempR.Left)
                                              {
                                                  mc.pos.X = ((Platform)plats[i]).hitBox.Left - mc.sprite.Width * mc.sprite.Scale;
                                                  mc.sprite.position.X = ((Platform)plats[i]).hitBox.Left - mc.sprite.Width * mc.sprite.Scale;
                                                  left = true;
                                              }
                                              // Right
                                              else
                                              {
                                                  mc.pos.X = ((Platform)plats[i]).hitBox.Right;
                                                  mc.sprite.position.X = ((Platform)plats[i]).hitBox.Right + 1;
                                                  right = true;
                                              } */
                                    }
                                    // Left or Right
                                    else
                                    {
                                        // Left
                                        if (centerPoint.X <= tempR.Left)
                                        {
                                            mc.pos.X = ((Platform)plats[i]).hitBox.Left - mc.sprite.Width * mc.sprite.Scale;
                                            mc.sprite.position.X = ((Platform)plats[i]).hitBox.Left - mc.sprite.Width * mc.sprite.Scale;
                                            left = true;
                                        }
                                        // Right
                                        else
                                        {
                                            mc.pos.X = ((Platform)plats[i]).hitBox.Right;
                                            mc.sprite.position.X = ((Platform)plats[i]).hitBox.Right + 1;
                                            right = true;
                                        }
                                    }
                                }
                            }
                        }

                        if (mc.pos.Y >= 650 || (top && bottom) || (right && left) || mc.energy <= 0)
                        {
                            mc.isDead = true;
                            dontStartYet = true;
                            SoundManager.Instance.playSound(SoundManager.Sound.death);
                        }
                    }
                    if (hasWon)
                    {
                        KeyboardState state = Keyboard.GetState();
                        if (state.IsKeyDown(Keys.Space))
                        {
                            hasWon = false;
                            plats = Platform.GetLevel(end, middle, endv, middlev, debugHit, gameFont);
                            mc.pos = playerStartPos;
                            powerUps = PowerUp.GetLevel(potionAtlas, debugHit);
                            mc = new MainCharacter(content.Load<Texture2D>("ProfAtlas"), playerStartPos, debugHit, gameFont);
                            cam = new Camera(new Rectangle(0, 0, ScreenManager.GraphicsDevice.Viewport.Width, ScreenManager.GraphicsDevice.Viewport.Height));
                            cam.Pos = new Vector2(mc.pos.X + (int)(mc.sprite.Height * mc.sprite.Scale * .5), mc.pos.Y + (int)(mc.sprite.Width * mc.sprite.Scale * .5));
                        }
                    }
                }
                else
                {
                    mc.Update(gameTime);
                    if (mc.deathCount >= 100)
                    {
                        plats = Platform.GetLevel(end, middle, endv, middlev, debugHit, gameFont);
                        powerUps = PowerUp.GetLevel(potionAtlas, debugHit);
                        mc.pos = playerStartPos;
                        mc = new MainCharacter(content.Load<Texture2D>("ProfAtlas"), playerStartPos, debugHit, gameFont);
                        dontStartYet = false;
                    }
                }
            }
        }

        public Vector2 findNearestCorner(Rectangle a, Rectangle b)
        {
            Vector2 corner = Vector2.Zero;

            Vector2 aCenter = new Vector2(a.Center.X, a.Center.Y);

            Vector2 topLeft = new Vector2(b.Left, b.Top);
            Vector2 topRight = new Vector2(b.Right, b.Top);
            Vector2 bottomLeft = new Vector2(b.Left, b.Bottom);
            Vector2 bottomRight = new Vector2(b.Right, b.Bottom);

            float topLeftDist = Vector2.Distance(aCenter, topLeft);
            float topRightDist = Vector2.Distance(aCenter, topRight);
            float bottomLeftDist = Vector2.Distance(aCenter, bottomLeft);
            float bottomRightDist = Vector2.Distance(aCenter, bottomRight);

            float closest = Math.Min(topLeftDist, Math.Min(topRightDist, Math.Min(bottomLeftDist, bottomRightDist)));

            if (closest == topLeftDist)
                return topLeft;
            else if (closest == topRightDist)
                return topRight;
            else if (closest == bottomLeftDist)
                return bottomLeft;
            else
                return bottomRight;
        }

        public override void HandleInput(GameTime gameTime, InputState input)
        {
            if (input == null)
                throw new ArgumentNullException("input");

            // Look up inputs for the active player profile.
            int playerIndex = (int)ControllingPlayer.Value;

            KeyboardState keyboardState = input.CurrentKeyboardStates[playerIndex];
            GamePadState gamePadState = input.CurrentGamePadStates[playerIndex];

            // The game pauses either if the user presses the pause button, or if
            // they unplug the active gamepad. This requires us to keep track of
            // whether a gamepad was ever plugged in, because we don't want to pause
            // on PC if they are playing with a keyboard and have no gamepad at all!
            bool gamePadDisconnected = !gamePadState.IsConnected &&
                                       input.GamePadWasConnected[playerIndex];


            PlayerIndex player;

            // Otherwise move the player position.
            if (pauseAction.Evaluate(input, ControllingPlayer, out player) || gamePadDisconnected)
            {
                ScreenManager.AddScreen(new PauseMenuScreen(), ControllingPlayer);
            }

            cam.Pos = new Vector2(mc.pos.X + (int)(mc.sprite.Height * mc.sprite.Scale * .5), mc.pos.Y + (int)(mc.sprite.Width * mc.sprite.Scale * .5));
        }

        public void Win()
        {
            //make special win menu
            //ScreenManager.AddScreen(new MainMenuScreen(), ControllingPlayer);
            hasWon = true;
        }

        public override void Draw(GameTime gameTime)
        {
            ScreenManager.GraphicsDevice.Clear(ClearOptions.Target,
                                                Color.Black, 0, 0);

            SpriteBatch spriteBatch = ScreenManager.SpriteBatch;
            if (hasWon)
            {
                SpriteFont font = content.Load<SpriteFont>("MainMenuFont");
                Texture2D square = content.Load<Texture2D>("alphaSquare");
                spriteBatch.Begin();
                spriteBatch.Draw(splash, Vector2.Zero, Color.White);
                spriteBatch.Draw(square, new Rectangle(90, 50, 460, 100), null, Color.Black, 0.0f, Vector2.Zero, SpriteEffects.None, 0f);
                spriteBatch.Draw(square, new Rectangle(90, 50, 460, 100), null, Color.Black, 0.0f, Vector2.Zero, SpriteEffects.None, 0f);
                spriteBatch.Draw(square, new Rectangle(90, 50, 460, 100), null, Color.Black, 0.0f, Vector2.Zero, SpriteEffects.None, 0f);
                spriteBatch.Draw(square, new Rectangle(90, 50, 460, 100), null, Color.Black, 0.0f, Vector2.Zero, SpriteEffects.None, 0f);
                spriteBatch.Draw(square, new Rectangle(90, 50, 460, 100), null, Color.Black, 0.0f, Vector2.Zero, SpriteEffects.None, 0f);
                spriteBatch.Draw(square, new Rectangle(90, 50, 460, 100), null, Color.Black, 0.0f, Vector2.Zero, SpriteEffects.None, 0f);
                spriteBatch.Draw(square, new Rectangle(90, 50, 460, 100), null, Color.Black, 0.0f, Vector2.Zero, SpriteEffects.None, 0f);
                spriteBatch.Draw(square, new Rectangle(90, 50, 460, 100), null, Color.Black, 0.0f, Vector2.Zero, SpriteEffects.None, 0f);
                spriteBatch.DrawString(font, "YOU WON!", new Vector2(100, 30), Color.White);
                spriteBatch.End();
            }
                
            if (!hasWon)
            {
                spriteBatch.Begin(SpriteSortMode.FrontToBack, null, null, null, null, null, cam.viewMatrix);
                // spriteBatch.Begin();


                for (int i = 0; i < plats.Count; i++)
                {
                    ((Platform)plats[i]).Draw(gameTime, spriteBatch, 1.0f);
                }

                for (int i = 0; i < powerUps.Count; i++)
                {
                    ((PowerUp)powerUps[i]).Draw(gameTime, spriteBatch, 1.0f);
                }

                mc.Draw(gameTime, spriteBatch);

                for (int i = 0; i < 3; i++)
                {
                    for (int j = 0; j < 10; j++)
                    {
                        spriteBatch.Draw(background, new Vector2((j - 1) * 800, (i - 1) * 600), null, Color.White, 0.0f, Vector2.Zero, 1.0f, SpriteEffects.None, 0.0f);
                    }
                }

                spriteBatch.Draw(energyBar, new Rectangle((int)cam.Pos.X - 300, (int)cam.Pos.Y - 275,
                    (int)(mc.energy * 200), 20), null, Color.White, 0.0f, Vector2.Zero, SpriteEffects.None, .9f);
                spriteBatch.End();

                // If the game is transitioning on or off, fade it out to black.
                if (TransitionPosition > 0 || pauseAlpha > 0)
                {
                    float alpha = MathHelper.Lerp(1f - TransitionAlpha, 1f, pauseAlpha / 2);

                    ScreenManager.FadeBackBufferToBlack(alpha);
                }
            }
        }
    }
}
